package cn.net.isir.core;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cn.net.isir.common.ResultObject;
import cn.net.isir.common.TokenManager;
import org.apache.log4j.Logger;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Objects;

/**
 * @author liuxubo
 * @filename BasicController.java
 * @package cn.net.isir.core
 * @email lxb@isir.net.cn
 * @date 2018/11/06
 * @comment
 * @since 1.7
 */
public abstract class BasicController<E extends BasicModel> {

    protected Logger logger = Logger.getLogger(this.getClass());

    private Class<E> eClass;

    public BasicController() {
        // 一定要放在构造函数里
        eClass = (Class<E>) getModelClass(0);// 0表示第一个泛型
    }

    /**
     * 获取运行对象中实际的泛型类型
     *
     * @param index 第index个泛型
     * @return 类型
     */
    private Class<?> getModelClass(int index) {
        Type genType = this.getClass().getGenericSuperclass();// 得到泛型父类
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();//一个泛型类可能有多个泛型形参，比如ClassName<T,K> 这里有两个泛型形参T和K，Class Name<T> 这里只有1个泛型形参T
        if (params.length - 1 < index) {
            return null;
        }
        return (Class) params[index];
    }

    private BasicService<E> service = null;

    /**
     * 根据用户id查询信息
     *
     * @param e userid放在
     * @return 列表
     */
    @RequestMapping(value = "/listByUser", method = RequestMethod.GET)
    public ResultObject selectListByUser(E e) {
        injectBasicService();
        e.setQueryUserId(TokenManager.getTokenId());
        return new ResultObject(200, "success", service.selectListByUser(e));
    }

    /**
     * 增加信息
     *
     * @param map 增加信息
     * @return 结果
     */
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public ResultObject add(@RequestBody Map map) {
        injectBasicService();
        E e = JSONObject.parseObject(JSON.toJSONString(map), eClass);
        return new ResultObject(200, "success", service.insert(e));
    }

    /**
     * 查询信息
     *
     * @param id 主键
     * @return 结果
     */
    @RequestMapping(value = "/info/{id}", method = RequestMethod.GET)
    public ResultObject query(@PathVariable String id) {
        injectBasicService();
        return new ResultObject(200, "success", service.selectByPrimaryKey(id));
    }

    /**
     * 保存修改信息
     *
     * @param map 信息实体类
     * @return 结果
     */
    @RequestMapping(value = "/save", method = RequestMethod.PUT)
    public ResultObject edit(@RequestBody Map map) {
        injectBasicService();
        E e = JSONObject.parseObject(JSON.toJSONString(map), eClass);
        return new ResultObject(200, "success", service.update(e));
    }

    /**
     * 删除信息
     *
     * @param id 主键
     * @return 结果
     */
    @RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
    public ResultObject delete(@PathVariable String id) {
        injectBasicService();
        BasicModel b = service.selectByPrimaryKey(id);
        //如果已经删除了,返回错误
        if (b == null || b.getIsValid() == 0) {
            return new ResultObject(500, "item not exist.", null);
        }
        return new ResultObject(200, "success", service.delete(id));
    }

    /**
     * 自动注入baseService
     */
    private void injectBasicService() {
        //第一次没有值的时候，才进行自动注入，否则不进行注入
        if (service != null) {
            return;
        }
        //反射获取所有字段
        java.lang.reflect.Field[] fields = this.getClass().getDeclaredFields();
        //循环所有字段
        for (java.lang.reflect.Field field : fields) {
            //判断当前字段是否有SetBasicDao注解
            boolean fieldHasAnno = field.isAnnotationPresent(SetBasicService.class);
            //如果没有注解，不进行处理
            if (!fieldHasAnno) {
                continue;
            }
            //判断当前注解的字段，是否是BaseDao的子类，不是则不进行处理
            if (!BasicService.class.isAssignableFrom(field.getType())) {
                continue;
            }
            //设置可访问性，如果不设置，访问的时候会抛出不可读异常
            field.setAccessible(true);
            //获取字段的值
            Object val = null;
            try {
                val = field.get(this);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            logger.info("auto inject:");
            logger.info(field.getName() + ":" + val);
            //赋值给basicDao
            try {
                this.service = (BasicService<E>) val;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        if (service == null) {
            throw new RuntimeException("Controller中的@SetBasicService注解设置不正确，请重新检查!泛型提示:[" + Objects.requireNonNull(this.getModelClass(0)).getTypeName() + "]");
        }
    }

}
